﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

using Awesomium.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;

using System.ComponentModel;

namespace Winz.FoeBot
{
    public class ProductionBot
    {
        public TimerPlus loopTimer;
        private Thread loopThread;

        private WebControl browser;
        private Point delta;
        private Bot.LogHandler Log;

        private BotStateEnum _state;
        public BotStateEnum State
        {
            get { return _state; }
            set
            {
                if (_state != value)
                {
                    _state = value;
                    OnPropertyChanged("State");
                }
            }
        }

        private string _status;
        public string Status
        {
            get { return _status; }
            set
            {
                _status = value;
                OnPropertyChanged("Status");
            }
        }



        private Rectangle lastCollect;
        private int collectTrys;


        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler ProdBotStarted;
        public event EventHandler ProdBotStopped;

        public ProductionBot()
        {
        }
        

        public ProductionBot(WebControl browser,Bot.LogHandler Log)
        {
            this.State = BotStateEnum.Stopped;
            this.Log = Log;
            this.loopTimer = new TimerPlus(300000);
            loopTimer.AutoReset = false;

            this.delta = new Point(0, 110);

            loopTimer.Elapsed += OnTimerLoopElapsed;
            this.browser = browser;

            this.loopThread = new Thread(() => { });
        }



        public void Start(int delaySeconds = 0)
        {
            Status = "Prod Bot starting";
            if (State == BotStateEnum.Started)
                return;

            loopTimer.Stop();
            this.State = BotStateEnum.Started;
            ProdBotStarted(this, new EventArgs());
            

            if(delaySeconds > 0 )
                Thread.Sleep(delaySeconds * 1000);

            lock (loopThread)
            {
                if (!loopThread.IsAlive)
                {
                    loopThread = new Thread(LoopTask);
                    loopThread.Start();
                }
            }
            Status = "Prod Bot started";
        }

        public void Stop()
        {
            Status = "Prod Bot stopping";
            browser.ProcessInput = Awesomium.Core.ViewInput.All;
            if (State == BotStateEnum.Stopped)
                return;

            this.State = BotStateEnum.Stopped;
            loopThread.Abort();
            loopTimer.Stop();
            browser.SetBotMode(false);
            ProdBotStopped(this, new EventArgs());
            Status = "Prod Bot stopped";
        }

        public void Pause()
        {

        }



        public void OnTimerLoopElapsed(object o, System.Timers.ElapsedEventArgs e)
        {
            loopTimer.Elapsed -= OnTimerLoopElapsed;
            lock (loopThread)
            {
                if (!loopThread.IsAlive)
                {
                    loopThread = new Thread(LoopTask);
                    loopThread.Start();
                }
                loopThread.Join();
            }
            loopTimer.Elapsed += OnTimerLoopElapsed;
        }





        public void LoopTask()
        {
            lastCollect = Rectangle.Empty;
            collectTrys = 0;

            loopTimer.Stop();

            Status = "ProdBot Running";
            Log("Start Loop");
            browser.ProcessInput = Awesomium.Core.ViewInput.None;
            browser.SetBotMode(true);
            Thread.Sleep(500);

            int i = 0;
            while (i < 5)
            {
                Status = "Checking";
                if (!Loop())
                    i++;
                else i = 0;
                Thread.Sleep(1000);
            }

            browser.LeftClick(100, 1000);
            Thread.Sleep(500);
            browser.SetBotMode(false);
            browser.ProcessInput = Awesomium.Core.ViewInput.All;

            Random random = new Random();
            double rand = (random.NextDouble() - 0.5) * 2;

            double r = 1 + rand * (double)Bot.settings.checkEveryRandomizePercent / 100;
            loopTimer.Interval = (double)Bot.settings.checkEvery * 60 * 1000 * r;
            loopTimer.Start();
            Log("Tmer interval left :{0} on:{1}", loopTimer.TimeLeft, loopTimer.Enabled);
        }

        public bool Loop()
        {

            Bitmap bitmap = new Bitmap(1, 1);

                browser.InvokeIfRequired((b) =>
                {
                    try
                    {
                        bitmap = new Bitmap(b.Width, b.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                        Rectangle bitmapRect = new Rectangle(0, 0, b.Width, b.Height);
                        b.DrawToBitmap(bitmap, bitmapRect);
                    }
                    catch (Exception e)
                    {
                        ;
                    }
                });
            if (bitmap.Height <= 1)
            {
                Log("Error while trying to analyse surface");
                bitmap.Dispose();
                return false;
            }

            List<Rectangle> list = bitmap.searchBitmap(Properties.Resources.zin, 0.1f, 6);
            if (list.Count > 0)
            {
                bitmap.Dispose();
                Rectangle btn = list.First();
                browser.LeftClick(btn.X + (btn.Width / 2), btn.Y + (btn.Height / 2));
                return true;
            }
            


            // Check if we are on the launch production page(Goods or Ressources)
            list = bitmap.searchBitmap(Properties.Resources.ProduceBtn, 0.1f, 6);
            if (list.Count == 6 || list.Count == 4)
            {
                bitmap.Dispose();
                Rectangle btn = Rectangle.Empty;
                if (list.Count == 6)
                {
                    Status = "Launching Ressources production";
                    Log("Launching Ressources production");
                    btn = list[Bot.settings.supplyDuration];
                }
                if (list.Count == 4)
                {
                    Status = "Launching Goods production";
                    Log("Launching Goods production");
                    btn = list[Bot.settings.goodsDuration];
                }
                browser.LeftClick(btn.X + (btn.Width / 2), btn.Y + (btn.Height / 2));
                Thread.Sleep(500);
                return true;
            }

            list = bitmap.searchBitmap(Properties.Resources.ProduceMilitaryBtn, 0.1f, 6);
            if (list.Count > 0)
            {
                bitmap.Dispose(); 
                Rectangle btn = Rectangle.Empty;
                btn = list.First();
                Status = "Launching Military production";
                Log("Launching Military production");
                browser.LeftClick(btn.X + (btn.Width / 2), btn.Y + (btn.Height / 2));
                return true;
            }

            list = GetRecoltPoints(bitmap, 15);
            if (list.Count > 0)
            {
                if(list.First().Contains(lastCollect.X + lastCollect.Width / 2, lastCollect.Y + lastCollect.Height / 2))
                    collectTrys++;
                else
                    collectTrys = 0;
                lastCollect = list.First();

                if (collectTrys > 2)
                {
                    Log("Third attempt on ({0},{1}) try with delta 0,300", list[0].X, list[0].Y);
                    List<Rectangle> l = new List<Rectangle> { list.First() }; 
                    browser.MouseHoverRectangles(l, new Point(0,300));
                    collectTrys = 0;
                    bitmap.Dispose();
                    return true;
                }
                
 

                Status = "Collecting";
                Log("Collecting (first : ({0},{1})", list[0].X, list[0].Y);
                browser.MouseHoverRectangles(list, delta);
                bitmap.Dispose();
                return true;
            }


            list = bitmap.searchBitmap(Properties.Resources.ProductionIdle, 0.1f, 10);
            if (list.Count > 0)
            {
                Status = "Clicking idle building";
                Log("Click Idle building, {0} found",list.Count);
                bitmap.Dispose();
                Rectangle r = list.First();
                browser.LeftClick(r.X + (r.Width / 2) + delta.X, r.Y + (r.Height / 2) + delta.Y);
                Thread.Sleep(300);
                browser.LeftClick(100, 1000);
                Thread.Sleep(100);
                return true;
            }

            list = bitmap.searchBitmap(Properties.Resources.CloseBtn, 0.1f, 1);
            if (list.Count > 0)
            {
                Status = "Closing open windows";
                Log("Click Close Button");
                bitmap.Dispose();
                Rectangle btn = list.First();
                browser.LeftClick(btn.X + (btn.Width / 2), btn.Y + (btn.Height / 2));
                return true;
            }

            list = bitmap.searchBitmap(Properties.Resources.BackToCityBtn, 0.1f, 3);
            if (list.Count > 0)
            {
                bitmap.Dispose();
                Rectangle btn = list.Last();
                browser.LeftClick(btn.X + (btn.Width / 2), btn.Y + (btn.Height / 2));
                return true;
            }


            bitmap.Dispose();
            Status = "Checking";
            Log("Nothing to do");
            return(false);

            
        }



        private static List<Rectangle> GetRecoltPoints(Bitmap bmp, int max)
        {

            Bitmap[] tmpls = {
                        Properties.Resources.ProductionFinished,
                        Properties.Resources.ProductionImprovedFinished,
                        Properties.Resources.ProductionPlundered,
                        Properties.Resources.ProuctionSlate
                             };


            List<Rectangle> prods = new List<Rectangle>();
            int res = 0;
            foreach (Bitmap template in tmpls)
            {
                prods.AddRange(bmp.searchBitmap(template, 0.1f, max - res));
                res = prods.Count;
                if (res >= max)
                    return prods;
            }
            return prods;
        }




        protected void OnPropertyChanged(string name)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name)); // notify subscribers
            }
        }

    }
}
